/******************************************************************************
 * * call_main.c - implementation of call main functions
 *
 * *(C) Copyright 2019 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/

#include "call_global.h"

/**********************
* GLOBAL VARIABLES
**********************/
UI_Call_Mng_t g_MMI_Call_Mng;

/**
 * initiate call module
 * param (in) void
 * return void
 */
VOID Call_Init_Req(VOID)
{
    Hal_Mem_Set(&g_MMI_Call_Mng, 0, sizeof(UI_Call_Mng_t));
    g_MMI_Call_Mng.FromAct = ACT_ID_ANY;
    g_MMI_Call_Mng.StatusAct = ACT_ID_ANY;
}

/**
 * call event handler
 * param (in) void
 * return void
 */
VOID Call_Event_Handle()
{
    // event and message dispatch
}

/**
 * clear call parameters
 * param (in) Index: UINT8
 * return  void
 */
VOID Call_Clear_Call_Paras(UINT8 Index)
{
    if (g_MMI_Call_Mng.Calls[Index] != NULL)
    {
        if (NULL != g_MMI_Call_Mng.Calls[Index]->Name)
        {
            Hal_Mem_Free(g_MMI_Call_Mng.Calls[Index]->Name);
        }
        if (NULL != g_MMI_Call_Mng.Calls[Index]->Number)
        {
            Hal_Mem_Free(g_MMI_Call_Mng.Calls[Index]->Number);
        }

        Hal_Mem_Free(g_MMI_Call_Mng.Calls[Index]);
        g_MMI_Call_Mng.Calls[Index] = NULL;
        Call_Set_Line_Off(Index);
    }
    else
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "calls index wrong or no active call\n");
    }
}

/**
 * Voice call request from contact
 * param Number: char*
 * return void
 */
VOID Call_Enter_Call_Paras(UINT8 Index, INT8 *Name, INT8 *Number)
{
    NV_UI_Call_ENumber_t Enumber;
    UI_Call_Params_t     *CallParams;
    UINT8                i;

    CallParams = (UI_Call_Params_t *)Hal_Mem_Alloc(sizeof(UI_Call_Params_t));
    Hal_Mem_Set(CallParams, 0, sizeof(UI_Call_Params_t));

    if (g_MMI_Call_Mng.Calls[Index] == NULL)
    {
        g_MMI_Call_Mng.Calls[Index] = CallParams;
        Call_Set_Line_On(Index);
    }
    else
    {
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_ERROR, "error\n");
        // Assert();
        return;
    }

    // set name
    if (NULL != Name)
    {
        CallParams->Name = (INT8 *)Hal_Mem_Alloc(strlen(Name) + 1);
        Hal_Mem_Set(CallParams->Name, 0, strlen(Name) + 1);
        Hal_Mem_Copy(CallParams->Name, Name, strlen(Name));
    }

    // set number
    CallParams->Number = (INT8 *)Hal_Mem_Alloc(strlen(Number) + 1);
    Hal_Mem_Set(CallParams->Number, 0, strlen(Number) + 1);
    Hal_Mem_Copy(CallParams->Number, Number, strlen(Number));

    // set name
    // set Emergency call flag
    CallParams->IsECall = FALSE;
    UI_NV_Read_Req(NV_SECTION_UI_CALL, CALL_NV_EMERGENCY_NUM_OFFSET, CALL_NV_EMERGENCY_NUM_SIZE, (UINT8 *)&Enumber);

    for (i = 0; i < Enumber.ENumberCnt; i++)
    {
        if (!strcmp(Enumber.ENumber[i], Number))
        {
            CallParams->IsECall = TRUE;
            break;
        }
    }

    CallParams->State = MMI_MODEM_CALL_STATE_INVALID;
} /* Call_Enter_Call_Paras */

/**
 * display timer timeout call back function
 * param (in) Para: UINT32
 * return  void
 */
VOID Call_Display_Timeout(VOID* Para)
{
    ACTIVITY_ID ActId = *(ACTIVITY_ID*)Para;
    printf("Call_Display_Timeout: ActId=%d\n", ActId);

    g_MMI_Call_Mng.DisplayTimer = NULL;
    g_MMI_Call_Mng.StatusAct = ACT_ID_ANY;

    if (ACT_ID_CALL_END == ActId)
    {   // if call end, go back to UI before call
        Call_UI_Go_Back();
    }
    else
    {   // others go back to previous UI
        Nav_Back(ActId);
    }

    Framework_Restart_Backlight_Timer();
}

/**
 * Call duration timer timeout call back function
 * param (in) Para: UINT32
 * return  void
 */
VOID Call_Duration_Timeout(VOID* Para)
{
    Call_Update_Call_Display(g_MMI_Call_Mng.CallDuration - 1);   // duration start from 1
    g_MMI_Call_Mng.CallDuration++;
    if (NULL != g_MMI_Call_Mng.Calls[0])
    {
        g_MMI_Call_Mng.Calls[0]->Duration++;
    }
    if (NULL != g_MMI_Call_Mng.Calls[1])
    {
        g_MMI_Call_Mng.Calls[1]->Duration++;
    }
}

/**
 * start to record call duration
 * param (in) void:
 * return  void
 */
VOID Call_Duration_Start(VOID)
{
    g_MMI_Call_Mng.CallDuration      = 1;

    UINT8 Para = 0;
    g_MMI_Call_Mng.CallDurationTimer =
        Hal_Timer_Start(UI_CALL_DURATION_TIMER_LEN, Call_Duration_Timeout, (VOID *)&Para, TRUE);
}

/**
 * start to record call duration
 * param (in) void:
 * return  void
 */
VOID Call_Duration_Stop(VOID)
{
    g_MMI_Call_Mng.CallDuration = 0;
    if (NULL != g_MMI_Call_Mng.CallDurationTimer)
    {
        Hal_Timer_Stop(g_MMI_Call_Mng.CallDurationTimer);
        g_MMI_Call_Mng.CallDurationTimer = NULL;
    }
}

/**
 * call speaker control
 * paras(in) SpkOn: BOOL  true means Speaker on
 * return void
 *
 */
VOID Call_Spk_Ctrl(BOOL SpkOn)
{
    UINT8 SpeakerVol;

    if (SpkOn)
    {
        g_MMI_Call_Mng.CallSpkStatus = HAL_CALL_SPK_ON;
        UI_NV_Read_Req(NV_SECTION_UI_CALL, CALL_NV_SPEAKER_OFFSET, 1, &SpeakerVol);
        Hal_Call_Speaker(HAL_CALL_SPK_ON, (HAL_SPEAKER_GAIN)SpeakerVol);
        Framework_Call_Loudspeaker_Ind(TRUE);
    }
    else
    {
        g_MMI_Call_Mng.CallSpkStatus = HAL_CALL_SPK_OFF;
        UI_NV_Read_Req(NV_SECTION_UI_CALL, CALL_NV_HANDSET_OFFSET, 1, &SpeakerVol);
        if(!Hal_Set_BT_Audio_Path((HAL_SPEAKER_GAIN)SpeakerVol))
            Hal_Call_Speaker(HAL_CALL_SPK_OFF, (HAL_SPEAKER_GAIN)SpeakerVol);
        Framework_Call_Loudspeaker_Ind(FALSE);
    }
}

/**
 * Get waiting paraindex
 * paras(in) void
 * return UINT8 param index of waiting call
 *
 */
UINT8 Call_Get_Waiting_Param_Index(VOID)
{
    UINT8 ParamIndex = 0;

    if (MMI_MODEM_CALL_STATE_WAITING == g_MMI_Call_Mng.Calls[ParamIndex]->State)
    {
        return(ParamIndex);
    }
    else
    {
        return(ParamIndex + 1);
    }
}

/**
 * Check call waiting present
 * paras(in) void
 * return UINT8 param index of waiting call
 *
 */
BOOL Call_Is_Call_Waiting_Present(VOID)
{
    UI_Call_Params_t *CallParams;

    // get pointer of the other calls
    CallParams = g_MMI_Call_Mng.Calls[(g_MMI_Call_Mng.ActiveIndex + 1) % 2];

    if (NULL == CallParams)
    {
        return(FALSE);
    }

    if (MMI_MODEM_CALL_STATE_WAITING == CallParams->State)
    {
        return(TRUE);
    }
    else
    {
        return(FALSE);
    }
}

/**
 * Get ParaIndex of first Free Line
 * paras(in) void
 * return UINT8 param index of free LINE
 *
 */
UINT8 Call_Get_Free_Line(VOID)
{
    if (0 == (UI_CALL_LINE_1 & g_MMI_Call_Mng.CallsBitMap))
    {
        return(0);
    }
    if (0 == (UI_CALL_LINE_2 & g_MMI_Call_Mng.CallsBitMap))
    {
        return(1);
    }

    return(UI_CALL_LINE_MAX);  // no free LINE
}

/**
 * Set Line on
 * paras(in) ParaIndex :UINT8
 * return void
 *
 */
VOID Call_Set_Line_On(UINT8 ParaIndex)
{
    g_MMI_Call_Mng.CallsBitMap |= (1 << ParaIndex);
}

/**
 * Set Line Off
 * paras(in) ParaIndex: UINT8
 * return void
 *
 */
VOID Call_Set_Line_Off(UINT8 ParaIndex)
{
    g_MMI_Call_Mng.CallsBitMap &= ~(1 << ParaIndex);
}

/**
 * go back to UI before calling ro incomming call
 * param (in) void:
 * return  void
 */
VOID Call_UI_Go_Back(VOID)
{
    ACTIVITY_ID ActId = g_MMI_Call_Mng.FromAct;
    g_MMI_Call_Mng.FromAct = ACT_ID_ANY;

    INT8 Index = Nav_Get_Index(ActId);

    if(Index >= 0)
    {
        Nav_Forward(ACT_ID_ANY, ActId, NULL, NULL);            // go back to UI before calling
    }
    else
    {
        ActId = Nav_Get_Prev(ACT_ID_CALL_INCOMING);

        if(ACT_ID_MAX == ActId)
        {
            ActId = Nav_Get_Prev(ACT_ID_CALL_MAIN);

            if(ACT_ID_MAX == ActId)
            {
                Nav_Home(ACT_ID_ANY);
                return;
            }
        }

        Nav_Forward(ACT_ID_ANY, ActId, NULL, NULL);     // go back to UI previous to CALL_INCOMING or CALL_MAIN
    }
}

/**
 * output call process and calls->state
 * param (in) void:
 * return  void
 */
VOID Call_Print_Call_Info(const INT8 *func)
{
    UINT8            i;
    UI_Call_Params_t *CallParams;

    UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "%s: Act Index %d; ", func, g_MMI_Call_Mng.ActiveIndex);
    switch (g_MMI_Call_Mng.CallProcess)
    {
    case UI_CALL_PROCESS_NULL:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "In Proc UI_CALL_PROCESS_NULL;\n");
        break;

    case UI_CALL_PROCESS_HOLD:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "In Proc UI_CALL_PROCESS_HOLD;\n");
        break;

    case UI_CALL_PROCESS_UNHOLD:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "In Proc UI_CALL_PROCESS_UNHOLD;\n");
        break;

    case UI_CALL_PROCESS_SWAP:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "In Proc UI_CALL_PROCESS_SWAP;\n");
        break;

    case UI_CALL_PROCESS_MT_REJECT:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "In Proc UI_CALL_PROCESS_MT_REJECT;\n");
        break;

    default:
        UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_3, "\n");
        break;
    }

    for (i = 0; i < 2; i++)
    {
        if (NULL != g_MMI_Call_Mng.Calls[i])
        {
            CallParams = g_MMI_Call_Mng.Calls[i];
            UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "SIM is %d, Index is %d; ", CallParams->SimId, CallParams->Index);
            switch (CallParams->State)
            {
            case MMI_MODEM_CALL_STATE_NULL:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_NULL\n");
                break;

            case MMI_MODEM_CALL_STATE_ACTIVE:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_ACTIVE\n");
                break;

            case MMI_MODEM_CALL_STATE_ALERTING:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_ALERTING\n");
                break;

            case MMI_MODEM_CALL_STATE_INVALID:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_INVALID\n");
                break;

            case MMI_MODEM_CALL_STATE_WAITING:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_WAITING\n");
                break;

            case MMI_MODEM_CALL_STATE_DIALING:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_DIALING\n");
                break;

            case MMI_MODEM_CALL_STATE_HOLDING:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_HOLDING\n");
                break;

            case MMI_MODEM_CALL_STATE_INCOMING:
                UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "Call state: MMI_MODEM_CALL_STATE_INCOMING\n");
                break;

            default:
                break;
            }
        }
    }
    UI_Log_Out(UI_SUB_MODULE_CALL, UI_LOG_LEVEL_TRACE_2, "\n");
} /* Call_Print_Call_Info */
